package com.jumi.microservice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jumi.microservice.common.constant.RequestConstant;
import com.jumi.microservice.common.exception.BusinessException;
import com.jumi.microservice.common.utils.ObjectUtils;
import com.jumi.microservice.constant.ExceptionEnum;
import com.jumi.microservice.constant.NumberConstant;
import com.jumi.microservice.constant.StatusEnum;
import com.jumi.microservice.domain.CategoryDO;
import com.jumi.microservice.domain.CategoryDTO;
import com.jumi.microservice.domain.CategoryQuery;
import com.jumi.microservice.domain.GoodsDO;
import com.jumi.microservice.mapper.CategoryMapper;
import com.jumi.microservice.mapper.GoodsMapper;
import com.jumi.microservice.service.CategoryService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.jumi.microservice.constant.CategoryEnum;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 商品分类管理service组件接口
 *
 * @author Administrator
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class CategoryServiceImpl implements CategoryService {

    /**
     * 商品分类管理mapper组件
     */
    @Autowired
    private CategoryMapper categoryMapper;

    /**
     * 商品分类名称标识符
     */
    private static final String CATEGORY_IDENTIFIER = ">";

    /**
     * 商品管理mapper组件
     */
    @Autowired
    private GoodsMapper goodsMapper;

    /**
     * 分页查询商品分类
     *
     * @param categoryQuery 查询条件
     * @return 商品分类列表
     */
    @Override
    public List<CategoryDTO> listCategoryByPage(CategoryQuery categoryQuery) {
        LambdaQueryWrapper<CategoryDO> categoryQueryWrapper = Wrappers.lambdaQuery();
        categoryQueryWrapper.eq(CategoryDO::getIsDel, StatusEnum.STATUS_NO.getCode());
        categoryQueryWrapper.eq(categoryQuery.getStatus() != null, CategoryDO::getStatus, categoryQuery.getStatus());
        categoryQueryWrapper.ge(StringUtils.isNotEmpty(categoryQuery.getCreateTimeFrom()), CategoryDO::getCreateTime, categoryQuery.getCreateTimeFrom());
        categoryQueryWrapper.le(StringUtils.isNotEmpty(categoryQuery.getCreateTimeTo()), CategoryDO::getCreateTime, categoryQuery.getCreateTimeTo());
        categoryQueryWrapper.ge(StringUtils.isNotEmpty(categoryQuery.getUpdateTimeFrom()), CategoryDO::getUpdateTime, categoryQuery.getUpdateTimeFrom());
        categoryQueryWrapper.le(StringUtils.isNotEmpty(categoryQuery.getUpdateTimeTo()), CategoryDO::getUpdateTime, categoryQuery.getUpdateTimeTo());
        categoryQueryWrapper.orderByDesc(CategoryDO::getId);

        List<CategoryDTO> categoryList = convertCategoryDoList2DtoList(categoryMapper.selectList(categoryQueryWrapper));
        categoryList.stream().filter(categoryDto -> categoryDto.getParentId() != null)
                .forEach(categoryDto -> {
                    CategoryDO category = categoryMapper.selectById(categoryDto.getParentId());
                    categoryDto.setCategoryName(category.getCategoryName() + CATEGORY_IDENTIFIER + categoryDto.getCategoryName());
                    categoryDto.setParentName(category.getCategoryName());
                });

        if (StringUtils.isNotEmpty(categoryQuery.getCategoryName())) {
            categoryList = categoryList.stream()
                    .filter(categoryDto -> categoryDto.getCategoryName().contains(categoryQuery.getCategoryName().trim()))
                    .collect(Collectors.toList());
        }
        return categoryList;
    }

    /**
     * 根据商品分类id查询商品分类
     *
     * @param id 商品分类id
     * @return 商品分类
     */
    @Override
    public CategoryDTO getCategoryById(Long id) {
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id == null);
        CategoryDO category = categoryMapper.selectById(id);

        ExceptionEnum.FAIL_NULL.doThrowIf(category == null);
        CategoryDTO categoryDto = convertCategoryDo2Dto(category);
        if (categoryDto.getParentId() != null) {
            category = categoryMapper.selectById(categoryDto.getParentId());
            categoryDto.setParentName(category.getCategoryName());
        }
        return categoryDto;
    }

    /**
     * 新增商品分类
     *
     * @param category 商品分类
     * @param request  HttpServletRequest
     */
    @Override
    public void saveCategory(CategoryDTO category, HttpServletRequest request) {
        ExceptionEnum.FAIL_NULL.doThrowIf(category == null);
        checkCategory(category);
        CategoryDO categoryDo = convertCategoryDto2Do(category);

        ExceptionEnum.FAIL_NAME_NULL.doThrowIf(request.getHeader(RequestConstant.ADMIN_NAME) == null);
        LocalDateTime localDateTime = LocalDateTime.now();
        categoryDo.setCreateTime(localDateTime);
        categoryDo.setUpdateTime(localDateTime);
        categoryDo.setCreater(request.getHeader(RequestConstant.ADMIN_NAME));
        categoryDo.setModifier(request.getHeader(RequestConstant.ADMIN_NAME));
        categoryMapper.insert(categoryDo);
    }

    /**
     * 更新商品分类
     *
     * @param category 商品分类
     * @param request  HttpServletRequest
     */
    @Override
    public void updateCategory(CategoryDTO category, HttpServletRequest request) {
        ExceptionEnum.FAIL_NULL.doThrowIf(category == null);
        checkCategory(category);
        CategoryDO categoryDo = convertCategoryDto2Do(category);

        ExceptionEnum.FAIL_NAME_NULL.doThrowIf(request.getHeader(RequestConstant.ADMIN_NAME) == null);
        LocalDateTime localDateTime = LocalDateTime.now();
        categoryDo.setUpdateTime(localDateTime);
        categoryDo.setModifier(request.getHeader(RequestConstant.ADMIN_NAME));
        categoryMapper.updateById(categoryDo);
    }

    /**
     * 删除商品分类
     *
     * @param ids     商品分类ids,支持批量删除,商品分类ID以逗号分割
     * @param request HttpServletRequest
     */
    @Override
    public void removeCategoryById(String ids, HttpServletRequest request) {
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(ids == null);

        List<CategoryDO> categories = categoryMapper.selectList(
                Wrappers.<CategoryDO>lambdaQuery()
                        .eq(CategoryDO::getIsDel, StatusEnum.STATUS_NO.getCode())
                        .apply("id in (" + ids + ")"));
        //只能删除禁用状态且未绑定商品的分类
        for (CategoryDO category : categories) {
            // 在启用状态下删除，弹出提示：启用状态下的分类，不能删除禁用状态下
            if (category.getStatus().equals(StatusEnum.STATUS_YES.getCode())) {
                throw new BusinessException(CategoryEnum.CATEGORY_STATUS_ABLED,
                        category.getCategoryName() + CategoryEnum.CATEGORY_STATUS_ABLED.getMessage(), null);
            }
            // 该分类绑定商品的，弹框提示：已绑定商品，不能删除
            List<GoodsDO> goods;
            if (category.getParentId() == null) {
                goods = goodsMapper.selectList(
                        Wrappers.<GoodsDO>lambdaQuery()
                                .select(GoodsDO::getId)
                                .eq(GoodsDO::getIsDel, StatusEnum.STATUS_NO.getCode())
                                .eq(GoodsDO::getCreatgroyFirst, category.getId()));
            } else {
                goods = goodsMapper.selectList(
                        Wrappers.<GoodsDO>lambdaQuery()
                                .select(GoodsDO::getId)
                                .eq(GoodsDO::getIsDel, StatusEnum.STATUS_NO.getCode())
                                .eq(GoodsDO::getCreatgroySecond, category.getId()));
            }
            if (goods != null && goods.size() > NumberConstant.NUMBER_ZERO.intValue()) {
                throw new BusinessException(CategoryEnum.CATEGORY_COMMODITY,
                        category.getCategoryName() + CategoryEnum.CATEGORY_COMMODITY.getMessage(), null);
            }
        }

        ExceptionEnum.FAIL_NAME_NULL.doThrowIf(request.getHeader(RequestConstant.ADMIN_NAME) == null);
        LambdaUpdateWrapper<CategoryDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CategoryDO::getIsDel, StatusEnum.STATUS_YES.getCode())
                .set(CategoryDO::getUpdateTime, LocalDateTime.now())
                .set(CategoryDO::getModifier, request.getHeader(RequestConstant.ADMIN_NAME))
                .in(CategoryDO::getId, Arrays.asList(ids.split(",")));
        categoryMapper.update(new CategoryDO(), updateWrapper);
    }

    /**
     * 商品分类状态启用/停用
     *
     * @param id      主键id
     * @param status  状态 (1启用，0.禁用)
     * @param request HttpServletRequest
     */
    @Override
    public void enableStatus(Long id, Integer status, HttpServletRequest request) {
        CategoryDO category = categoryMapper.selectById(id);
        ExceptionEnum.FAIL_NULL.doThrowIf(category == null);
        ExceptionEnum.FAIL_NAME_NULL.doThrowIf(request.getHeader(RequestConstant.ADMIN_NAME) == null);

        category.setStatus(status);
        category.setModifier(request.getHeader(RequestConstant.ADMIN_NAME));
        category.setUpdateTime(LocalDateTime.now());
        categoryMapper.updateById(category);

        if (category.getParentId() != null && status.equals(StatusEnum.STATUS_YES.getCode())) {
            CategoryDO categoryParent = categoryMapper.selectById(category.getParentId());
            if (categoryParent.getStatus().equals(StatusEnum.STATUS_NO.getCode())) {
                categoryParent.setStatus(status);
                categoryParent.setModifier(request.getHeader(RequestConstant.ADMIN_NAME));
                categoryParent.setUpdateTime(LocalDateTime.now());
                categoryMapper.updateById(categoryParent);
            }
        }

        //禁用父类，则禁用所有子类
        if (category.getParentId() == null && status.equals(StatusEnum.STATUS_NO.getCode())) {
            LambdaUpdateWrapper<CategoryDO> categoryWrapper = new LambdaUpdateWrapper<>();
            categoryWrapper.set(CategoryDO::getStatus, status)
                    .set(CategoryDO::getModifier, request.getHeader(RequestConstant.ADMIN_NAME))
                    .set(CategoryDO::getUpdateTime, LocalDateTime.now())
                    .eq(CategoryDO::getParentId, id);
            categoryMapper.update(new CategoryDO(), categoryWrapper);
        }

    }

    /**
     * 返回商品分类列表(给商品管理列表页使用)
     *
     * @param type 如果不为null 取一级菜单
     * @return 商品分类列集合
     */
    @Override
    public List<CategoryDTO> listCategory(Long type) {
        LambdaQueryWrapper<CategoryDO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CategoryDO::getIsDel, StatusEnum.STATUS_NO.getCode());
        wrapper.eq(CategoryDO::getStatus, StatusEnum.STATUS_YES.getCode());
        if (type != null) {
            wrapper.isNull(CategoryDO::getParentId);
        } else {
            wrapper.isNotNull(CategoryDO::getParentId);
        }
        List<CategoryDO> categories = categoryMapper.selectList(wrapper);
        List<CategoryDTO> categoryDtos = convertCategoryDoList2DtoList(categories);

        categoryDtos.stream().filter(categoryDto -> categoryDto.getParentId() != null)
                .forEach(categoryDto -> {
                    CategoryDO category = categoryMapper.selectById(categoryDto.getParentId());
                    categoryDto.setCategoryName(category.getCategoryName() + CATEGORY_IDENTIFIER + categoryDto.getCategoryName());
                    categoryDto.setParentName(category.getCategoryName());
                });
        return categoryDtos;
    }

    /**
     * 返回商品分类列表
     *
     * @param id 商品分类id
     * @return 商品分类列集合
     */
    @Override
    public List<CategoryDTO> listCategoryById(Long id) {
        LambdaQueryWrapper<CategoryDO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CategoryDO::getIsDel, StatusEnum.STATUS_NO.getCode());
        wrapper.eq(CategoryDO::getStatus, StatusEnum.STATUS_YES.getCode());
        if (id != null) {
            wrapper.eq(CategoryDO::getParentId, id);
        } else {
            wrapper.isNull(CategoryDO::getParentId);
        }
        List<CategoryDO> categories = categoryMapper.selectList(wrapper);
        return convertCategoryDoList2DtoList(categories);
    }

    /**
     * 检查是否存在未删除状态的同名的商品分类名称
     *
     * @param category 商品分类DTO
     */
    private void checkCategory(CategoryDTO category) {
        List<CategoryDO> categoryIdList = categoryMapper.selectList(
                Wrappers.<CategoryDO>lambdaQuery()
                        .select(CategoryDO::getId)
                        .eq(CategoryDO::getCategoryName, category.getCategoryName())
                        .eq(CategoryDO::getIsDel, StatusEnum.STATUS_NO.getCode()));

        if (categoryIdList.size() > 0) {
            throw new BusinessException(CategoryEnum.CATEGORY_HAS_EXISTED);
        }
    }

    /**
     * 将商品分类DO对象转换为DTO对象
     *
     * @param category 商品分类DO
     * @return CategoryDTO 商品分类DTO
     */
    private CategoryDTO convertCategoryDo2Dto(CategoryDO category) {
        CategoryDTO categoryDto = null;
        try {
            categoryDto = category.clone(CategoryDTO.class);
        } catch (Exception e) {
            ExceptionEnum.FAIL_CHANGE.newException();
        }
        return categoryDto;
    }

    /**
     * 将商品分类DTO对象转换为DO对象
     *
     * @param categoryDTO 商品分类DTO
     * @return Category 商品分类DO
     */
    private CategoryDO convertCategoryDto2Do(CategoryDTO categoryDTO) {
        CategoryDO category = null;
        try {
            category = categoryDTO.clone(CategoryDO.class);
        } catch (Exception e) {
            ExceptionEnum.FAIL_CHANGE.newException();
        }
        return category;
    }

    /**
     * 将商品分类DO对象集合转换为DTO对象集合
     *
     * @param categories 商品分类DO集合
     * @return List<CategoryDTO> 商品分类DTO对象集合
     */
    private List<CategoryDTO> convertCategoryDoList2DtoList(List<CategoryDO> categories) {
        List<CategoryDTO> categoryDtoList = null;
        try {
            categoryDtoList = ObjectUtils.convertList(categories, CategoryDTO.class);
        } catch (Exception e) {
            ExceptionEnum.FAIL_CHANGE.newException();
        }
        return categoryDtoList;
    }
}
